using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Arroguella.Entities;

namespace Arroguella.Tiles
{
    /// <summary>
    /// This represents a small section of the GameMap that is responsible for everything within it.
    /// </summary>
    public class Tile : GameComponent
    {
        #region Constructors

        /// <summary>
        /// Default constructor.
        /// </summary>
        public Tile(Game game)
            : base(game)
        {
            Color = Color.DarkSlateGray;
            Coords = new Vector2(0, 0);
        }

        /// <summary>
        /// Constructs a tile
        /// </summary>
        public Tile(Game game, Vector2 coordinates)
            : base(game)
        {
            Coords = coordinates;
            Color = Color.DarkSlateGray;
        }

        /// <summary>
        /// Constructs a tile
        /// </summary>
        public Tile(Game game, Vector2 coordinates, Color color)
            : base(game)
        {
            Coords = coordinates;
            Color = color;
        }

        /// <summary>
        /// Constructs a tile
        /// </summary>
        public Tile(Game game, Vector2 coordinates, Color color, bool isBlocking)
            : base(game)
        {
            Coords = coordinates;
            Color = color;
            IsBlocking = isBlocking;
        }

        #endregion

        #region Events
        #endregion

        #region Methods

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }

        /// <summary>
        /// Adds an environmental entity to the Tile's list of objects.
        /// Also ensures HasEnvironmentalEntity is now true;
        /// Environmental Entities can NOT be removed from the Objects list.
        /// </summary>
        public void AddEnvironmentalEntity(Entity env)
        {
            Objects.Add(env);
            HasEnvironmentalEntity = true;
        }

        #endregion

        #region Properties

        /// <summary>
        /// A particular label, symbol, or character to draw on the tile.
        /// This will override any entity symbols on the tile.
        /// </summary>
        protected string Label { get; set; }

        /// <summary>
        /// All the entities within the tile.
        /// </summary>
        public List<Entity> Objects = new List<Entity>();

        /// <summary>
        /// A particular symbol or character that represents the tile,
        /// or an object on the tile.
        /// This will draw on the tile unless there is a Label set.
        /// </summary>
        public string Symbol
        {
            get
            {
                if (string.IsNullOrEmpty(Label))
                {
                    if (IsBlocking)
                    {
                        if (Arroguella.OldSchoolModeEnabled)
                        {                          
                            return @"#";
                        }
                    }
                    else
                    {
                        // Display the first symbol we come to.
                        foreach (Entity obj in Objects)
                        {
                            if (!string.IsNullOrEmpty(obj.Symbol.ToString()) && obj.IsVisible)
                            {
                                return obj.Symbol.ToString();
                            }
                        }

                        // Empty floor tile with no Entities
                        if (Arroguella.OldSchoolModeEnabled)
                        {                          
                            return @".";
                        }
                    }                    
                }
                else
                {
                    return Label;
                }

                return string.Empty;
            }
        }

        /// <summary>
        /// The color used to draw the Symbol
        /// </summary>
        public Color SymbolColor
        {
            get
            {
                if (string.IsNullOrEmpty(Label))
                {
                    // Display the first symbol we come to.
                    foreach (Entity obj in Objects)
                    {
                        if (obj.IsVisible && obj.Color != null)
                        {
                            return obj.Color;
                        }
                    }
                }


                return symbolColor;
            }
        }
        private Color symbolColor = Color.Gray;

        /// <summary>
        /// The (x, y) coordinates of this tile on the GameMap.
        /// The origin tile (0, 0) is in the top-left corner.
        /// </summary>
        public Vector2 Coords { get; set; }

        /// <summary>
        /// The size of the tile, in pixels.
        /// </summary>
        public static Vector2 Size = new Vector2(16, 16);

        /// <summary>
        /// The color of the tile itself.
        /// </summary>
        public Color Color
        { 
            get
            {
                if (LightIntensity != 0)
                {
                    int adj = (int)(255 * LightIntensity);
                    return Color.FromNonPremultiplied(color.R + adj, color.G + adj, color.B + adj, color.A);
                }
                else if (LightIntensityRed != 0 || LightIntensityGreen != 0 || LightIntensityBlue != 0)
                {
                    int adjR = (int)(255 * LightIntensityRed);
                    int adjG = (int)(255 * LightIntensityGreen);
                    int adjB = (int)(255 * LightIntensityBlue);

                    return Color.FromNonPremultiplied(color.R + adjR, color.G + adjG, color.B + adjB, color.A);
                }
                else
                {
                    return color;
                }
            }
            set { color = value; } 
        }
        private Color color = Color.Black;

        /// <summary>
        /// Whether or not the player is currently in the tile.
        /// </summary>
        public bool IsPlayerOccupied { get; set; }

        /// <summary>
        /// A flag to determine if the player should start here.
        /// </summary>
        public bool PlayerStart { get; set; }

        /// <summary>
        /// Whether or not this tile physically blocks movement.
        /// If true, this tile represents a physical obstacle.
        /// If false, this tile can be moved through, as if it were just a piece of floor.
        /// </summary>
        public bool IsBlocking { get; set; }

        /// <summary>
        /// Whether or not this tile contains an environmental entity.
        /// </summary>
        public bool HasEnvironmentalEntity { get; private set; }

        /// <summary>
        /// The intensity of basic lighting on the tile.
        /// A value of 0 means it will appear as the base Color.
        /// A value of -1 means it will be completely dark (black).
        /// A value of 1 means it will be completely bright (white).
        /// A value between 0 and 1 will increase the current color towards white.
        /// A value between -1 and 0 will decrease the current color towards black.
        /// </summary>
        public float LightIntensity { get; set; }

        /// <summary>
        /// The intensity of red lighting on the tile.
        /// A value of 0 means it will appear as the base Color.
        /// A value of -1 means it will be completely dark (black).
        /// A value of 1 means it will be completely bright (red).
        /// A value between 0 and 1 will increase the current color towards red.
        /// A value between -1 and 0 will decrease the current color towards black.
        /// </summary>
        public float LightIntensityRed { get; set; }

        /// <summary>
        /// The intensity of green lighting on the tile.
        /// A value of 0 means it will appear as the base Color.
        /// A value of -1 means it will be completely dark (black).
        /// A value of 1 means it will be completely bright (green).
        /// A value between 0 and 1 will increase the current color towards green.
        /// A value between -1 and 0 will decrease the current color towards black.
        /// </summary>
        public float LightIntensityGreen { get; set; }

        /// <summary>
        /// The intensity of blue lighting on the tile.
        /// A value of 0 means it will appear as the base Color.
        /// A value of -1 means it will be completely dark (black).
        /// A value of 1 means it will be completely bright (blue).
        /// A value between 0 and 1 will increase the current color towards blue.
        /// A value between -1 and 0 will decrease the current color towards black.
        /// </summary>
        public float LightIntensityBlue { get; set; }

        /// <summary>
        /// Whether or not the Tile has been seen or visited by the Player.
        /// This is used for Fog of War functionality.
        /// </summary>
        public bool IsExplored { get; set; }

        /// <summary>
        /// Once set to true, this tile will never be drawn.
        /// </summary>
        protected internal bool NeverDraw { get; set; }

        public bool IsHighlight { get; set; }

        #endregion

    }
}
